<template>
  <div ref="scrollerRef" class="scroller">
    <canvas v-show="show"></canvas>
    <slot></slot>
  </div>
</template>
<script>
import { ref, onMounted, reactive, onUpdated } from "vue";
export default {
  name: "AndroidStyleScroller",
  setup() {
    const scrollerRef = ref(null);
    const show = ref(false);
    const size = reactive({ width: 0, height: 0 });
    let cvs = null;
    let ctx = null;

    onMounted(() => {
      cvs = scrollerRef.value.children[0];
      ctx = cvs.getContext("2d");
      cvs.width = size.width = scrollerRef.value.clientWidth*(1.2);
      cvs.height = size.height = scrollerRef.value.scrollHeight;
      window.onresize = () => {
        cvs.width = size.width = scrollerRef.value.clientWidth*(1.2);
        cvs.height = size.height = scrollerRef.value.scrollHeight;
      };
      initScroller();
    });

    onUpdated(()=>{
      cvs.width = size.width = scrollerRef.value.clientWidth*(1.2);
      cvs.height = size.height = scrollerRef.value.scrollHeight;
    })

    function initScroller() {
      //初始化拖动水波纹
      const scroller = scrollerRef.value;
      const maxMove = 150;
      let startY = 0;
      let startWave = false;

      function draw(x, y) {
        y = Math.abs(y) < maxMove ? y : y > 0 ? maxMove : -maxMove;
        let a = Math.abs(y) / 250;
        a = a > 0.5 ? 0.5 : a;
        ctx.clearRect(0, 0, size.width, size.height);
        ctx.fillStyle = "rgba(30,144,255," + a + ")";
        ctx.beginPath();
        if (y > 0) {
          ctx.moveTo(0, 0);
          ctx.quadraticCurveTo(x, y, size.width, 0);
        } else {
          ctx.moveTo(0, size.height);
          ctx.quadraticCurveTo(x, size.height + y, size.width, size.height);
        }
        ctx.fill();
      }

      function touchMove(event) {
        event.stopPropagation()
        if (
          scroller.scrollTop == 0 ||
          scroller.scrollHeight - scroller.clientHeight == scroller.scrollTop
        ) {
          if (startWave) {
            const x = event.changedTouches[0].pageX;
            let y = (event.changedTouches[0].pageY - startY) * 0.3;
            draw(x, y);
          } else {
            show.value = true;
            startWave = true;
            startY = event.changedTouches[0].pageY;
          }
        }
      }

      function touchEnd(event) {
        scroller.removeEventListener("touchmove", touchMove);
        scroller.removeEventListener("touchend", touchEnd);
        startWave = false;
        const x = event.changedTouches[0].pageX;
        let y = (event.changedTouches[0].pageY - startY) * 0.3;
        const direction = y > 0 ? 1 : -1;
        y = Math.abs(y);

        function step(timestamp) {
          if (y > 0) {
            y -= 6;
            y = y < 0 ? 0 : y;
            draw(x, y * direction);
            window.requestAnimationFrame(step);
          } else {
            show.value = false;
          }
        }
        window.requestAnimationFrame(step);
      }

      scroller.addEventListener("touchstart", (event) => {
        scroller.addEventListener("touchmove", touchMove);
        scroller.addEventListener("touchend", touchEnd);
      });
    }

    return {
      scrollerRef,
      show,
    };
  },
};
</script>
<style lang="less" scoped>
.scroller {
  height: 100%;
  min-height: 200px;
  position: relative;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  > canvas {
    left: 50%;
    top: 0;
    position: absolute;
    transform: translateX(-50%);
    z-index: 1;
  }
}
</style>
